package org.moonlight.jvm.rtda.exclusive;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.moonlight.jvm.rtda.share.heap.classmember.Method;

/**
 * 运行时数据区 - 线程独占区 - 线程
 *
 * 线程独占区是在创建线程时才分配给对应的线程，线程退出时销毁。
 *
 * 线程独占区主要是用于模拟CPU，辅助执行Java字节码。线程独占区中包含有 虚拟机栈，本地方法栈，程序计数器。
 *   1. 虚拟机栈: 描述的是Java方法执行的内存模型，生命周期和线程相同。可能产生 SOE、OOM
 *              每个方法执行时都会创建一个栈帧，栈帧中包含：操作数栈、局部变量表、动态连接、方法出口、指向常量池的指针等等方法执行所需要的信息
 *                 a.首先给线程分配一个栈空间，每个线程都有自己的线程栈
 *                 b.在线程执行方法的时候，会把当前方法的相关数据(比如参数/局部变量数/方法栈深),封装成栈帧压入线程栈中
 *                   如果在执行时发现方法里又套了其他方法,那么又会把被调用的方法封装成另一个栈帧,压到栈顶并执行,执行完
 *                   后弹出,如果有返回值就拿到它的返回值,返回给开始执行的那个方法(调用者)并继续执行,如果整个方法执行完毕,线程栈销毁,线程释放资源(如果没有使用线程池的话)
 *   2. 本地方法栈: 和虚拟机栈差不多，只不过虚拟机栈是给虚拟机执行Java方法服务的，本地方法栈是给native方法服务的。可能产生SOE、OOM。
 *   3. 程序计数器(PC): 记录当前线程所执行的字节码的行号. 条件分支、循环跳转、异常处理、线程恢复 都依赖于它. 没有OOM异常
 *                如果当前执行的方法是Java方法那么程序计数器中存储的就是当前正在执行的字节码的行号，否则，当前方法是本地方法，程序计数器中的值没有明确定义
 *
 * 具体实现请见:
 *   1. 线程 {@link Thread}
 *   2. 虚拟机栈 {@link JvmStack}
 *   3. 虚拟机栈帧 {@link Frame}
 *   4. 操作数栈 {@link OperandStack} 局部变量表 {@link LocalVars}
 *   5. 承载元素(每个元素至少可以容纳一个int或引用值，两个连续的元素可以容纳一个long或double值)的槽位 {@link Slot}
 *
 * @author Moonlight
 * @createTime 2023/8/16 10:06
 **/
@EqualsAndHashCode
public class Thread {

    /** 程序计数器 Program Counter - 模拟的寄存器 **/
    @Getter
    @Setter
    private int pc;
    private final JvmStack jvmStack;

    public Thread() {
        this.jvmStack = new JvmStack(1024);
    }

    public void pushFrame(Frame frame) {
        this.jvmStack.push(frame);
    }

    public Frame popFrame() {
        return this.jvmStack.pop();
    }

    public Frame currentFrame() {
        return this.jvmStack.top();
    }

    public Frame topFrame() {
        return this.jvmStack.top();
    }

    public Frame newFrame(Method method) {
        return new Frame(this, method);
    }

    public boolean isStackEmpty() {
        return this.jvmStack.isEmpty();
    }

    public void clearStack() {
        this.jvmStack.clear();
    }

    public Frame[] getFrames() {
        return this.jvmStack.getFrames();
    }

}
